package de.tum.in.eist.im.server.Chat;

import java.util.ArrayList;
import java.util.List;

import de.tum.in.eist.im.client.Chat.ChatPanelService;
import de.tum.in.eist.im.server.Datastore.DatastoreManager;
import de.tum.in.eist.im.shared.ChatChannel.ChatChannel;
import de.tum.in.eist.im.shared.User.User;

import com.google.appengine.api.channel.ChannelMessage;
import com.google.appengine.api.channel.ChannelService;
import com.google.appengine.api.channel.ChannelServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class ChatPanelServiceImpl extends RemoteServiceServlet implements
		ChatPanelService {

	 // static list of all online users
	private static List<User> userList = new ArrayList<User>();
	
	// static list of open channels
	private static List<ChatChannel> openChatChannels = new ArrayList<ChatChannel>();
	private static List<ChatChannel> openPrivateChatChannels = new ArrayList<ChatChannel>();
	
	/**
	 * returns the id of a channel
	 * @param channelTitle the title of the channel
	 * @return the channel id
	 */
	@Override
	public Long getChatChannelId (String channelTitle) {
		DatastoreManager datastore = new DatastoreManager();
		return datastore.getChatChannelId(channelTitle);
	}
	
	/**
	 * returns a token of the username from the server
	 * @return token
	 */
	public String getApiToken(String username) {
		ChannelService channelService = ChannelServiceFactory.getChannelService();
		String token = channelService.createChannel(username);
		System.out.println("sending back channel api token : " + token);
		return token;
	}
	
	/**
	 * return the private chat channel id to the client
	 * @param thisUser the user calling this method
	 * @param otherUser the other user
	 * @return the chat chat channel id
	 */
	@Override
	public Long getPrivateChatChannelId (User thisUser, User otherUser) {
		DatastoreManager datastore = new DatastoreManager();
		
		boolean found = false;
		User otherUserFound = null;
		for (User u : userList) {
			if (u.getUsername().equals(otherUser.getUsername())) {
				found = true;
				otherUserFound = u;
				break;
			}
		}
		
		if (found) {
			// request chat tab at the other user
			addChatTabAtTheOtherUser(thisUser, otherUserFound);
		}
		return datastore.getPrivateChatChannelId(thisUser, otherUser);
	}

	
	/**
	 * force to open a chat tab at the other user
	 * @param thisUser this user calling the method
	 * @param otherUserFound the other user
	 */
	public void addChatTabAtTheOtherUser(User thisUser, User otherUserFound) {
		// build the JSON string
		String result = "{{\"type\":\"4\"}, {\"thisUser\":\"" + thisUser.getUsername() + "\"}, {\"otherUser\":\"" + otherUserFound.getUsername() + "\"}";
		result += "}";

		// push the message to all user
		ChannelService channelService = ChannelServiceFactory.getChannelService();
		channelService.sendMessage(new ChannelMessage(otherUserFound.getUsername(), result));
	}
	
	/**
	 * add a user to the List of all! online users
	 * @param user the user to add to the list of online users
	 * @return true
	 */
	@Override
	public Boolean addUserAsOnline (User user) {
		boolean found = false;
		
		for (User u : userList) {		
			if (u.getUsername().equals(user.getUsername()))
				found = true;
		}
			
		System.out.println("ASDF");
		if (!found) {
			System.out.println("Asdf");
			userList.add(user);
			// send list of all user to all user
			this.getOnlineUsersFromServer();
		}
		
		return true;
	}

	/**
	 * removes the user of the list of all! online users
	 * @param user the user to delete from the list
	 * @return true
	 */
	@Override
	public Boolean removeUserAsOnline (User user) {
		User removeUser = null;
		
		for (User u : userList) {
			if (u.getUsername().equals(user.getUsername()))
				removeUser = u;
		}
		
		if (null != removeUser)
			userList.remove(removeUser);
		
		for (ChatChannel cC : openChatChannels) {
			cC.removeUserFromChatChannel(user);
			// send list of all user to all user
			this.getOnlineUsersFromServer();
		}
		
		return true;
	}

	/**
	 * returns the list of all online users!
	 * @return List of all Online users
	 */
	public void getOnlineUsersFromServer() {	

		String result = this.getOnlineUsersFromServerAsString();
		// push the message to all user
		ChannelService channelService = ChannelServiceFactory.getChannelService();
		for (User u : userList) {
			channelService.sendMessage(new ChannelMessage(u.getUsername(), result));
		}
	}
	
	/**
	 * retusn all online user from the server as a string
	 * @return json string of all online user
	 */
	public String getOnlineUsersFromServerAsString() {
		// build the JSON string
		String result = "{{\"type\":\"2\"}";
		for (User u : userList) {
			result += ", {\"user\":\"" + u.getUsername() + "\"}";
		}
		result += "}";
		System.out.println(result);
		return result;
	}

	/**
	 * add a ChatChannel object to the List of all! open chat channels
	 * @param chatChannel the ChatChannel object to add to the list of all! open chat channels
	 * @return true
	 */
	@Override
	public Boolean addGroupAsOpen(ChatChannel chatChannel) {
		boolean found = false;
		for (ChatChannel cC : openChatChannels) {
			if (cC.getChatId().equals(chatChannel.getChatId())) 
				found = true;
		}
		
		if (!found) {
			openChatChannels.add(chatChannel);
			this.getOpenGroups();
		}
		
		return true;
	}
	
	/**
	 * add a private ChatChannel object to the List of all! open chat channels
	 * @param chatChannel the ChatChannel object to add to the list of all! open chat channels
	 * @return true
	 */
	@Override
	public Boolean addPrivateGroupAsOpen(ChatChannel chatChannel) {
		boolean found = false;
		for (ChatChannel cC : openPrivateChatChannels) {
			if (cC.getChatId().equals(chatChannel.getChatId())) 
				found = true;
		}
		
		if (!found) {
			openPrivateChatChannels.add(chatChannel);
			this.getOpenGroups();
		}
		
		return true;
	}

	/**
	 * remove a ChatChannel object of the List of all! open chat channels
	 * @param chatChannel the ChatChannel object to remove of the List of all! open ChatChannels
	 * @return true
	 */
	@Override
	public Boolean removeGroupAsOpen(ChatChannel chatChannel) {
		ChatChannel removeChatChannel = null;
		
		for (ChatChannel cC : openChatChannels) {
			if (cC.getChatId().equals(chatChannel.getChatId()))
				removeChatChannel = cC;
		}
		
		if (null != removeChatChannel) {
			userList.remove(removeChatChannel);
			this.getOpenGroups();
		}
		
		return true;
	}

	/**
	 * returns the list of all! open chat channels
	 * @return List of all open chat channels
	 */
	public void getOpenGroups() {

		String result = this.getOnlineGroupsFromServerAsString();
		
		// push the message to all user
		ChannelService channelService = ChannelServiceFactory.getChannelService();
		for (User u : userList) {
			channelService.sendMessage(new ChannelMessage(u.getUsername(), result));
		}
	}

	/**
	 * returns a list of all open channels
	 * @return list of all open channels
	 */
	public static List<ChatChannel> getOpenChannels() {
		return openChatChannels;
	}

	/**
	 * returns a list of all open private channels
	 * @return list of all open private channels
	 */
	public static List<ChatChannel> getOpenPrivateChannels() {
		return openPrivateChatChannels;
	}
	
	/**
	 * get all online groups from the server as a json string
	 * @return all online groups as a json string
	 */
	@Override
	public String getOnlineGroupsFromServerAsString() {
		// build the JSON string
		String result = "{{\"type\":\"3\"}";
		for (ChatChannel cC : openChatChannels) {
			result += ", {\"channelTitle\":\"" + cC.getTitle() + "\"}, {\"channelId\":\"" + cC.getChatId() + "\"}";
		}
		result += "}";
		return result;
	}
}
